@@ -0,0 +1,92 @@ |
||
| 1 |
+module Agents |
|
| 2 |
+ class BasecampAgent < Agent |
|
| 3 |
+ cannot_receive_events! |
|
| 4 |
+ |
|
| 5 |
+ description <<-MD |
|
| 6 |
+ The BasecampAgent checks a Basecamp project for new Events |
|
| 7 |
+ |
|
| 8 |
+ It is required that you enter your Basecamp credentials (`username` and `password`). |
|
| 9 |
+ |
|
| 10 |
+ You also need to provide your Basecamp `user_id` and the `project_id` of the project you want to monitor. |
|
| 11 |
+ If you have your Basecamp project opened in your browser you can find the user_id and project_id as follows: |
|
| 12 |
+ |
|
| 13 |
+ `https://basecamp.com/` |
|
| 14 |
+ user_id |
|
| 15 |
+ `/projects/` |
|
| 16 |
+ project_id |
|
| 17 |
+ `-explore-basecamp` |
|
| 18 |
+ MD |
|
| 19 |
+ |
|
| 20 |
+ event_description <<-MD |
|
| 21 |
+ Events are the raw JSON provided by the Basecamp API. Should look something like: |
|
| 22 |
+ |
|
| 23 |
+ {
|
|
| 24 |
+ "creator": {
|
|
| 25 |
+ "fullsize_avatar_url": "https://dge9rmgqjs8m1.cloudfront.net/global/dfsdfsdfdsf/original.gif?r=3", |
|
| 26 |
+ "avatar_url": "http://dge9rmgqjs8m1.cloudfront.net/global/dfsdfsdfdsf/avatar.gif?r=3", |
|
| 27 |
+ "name": "Dominik Sander", |
|
| 28 |
+ "id": 123456 |
|
| 29 |
+ }, |
|
| 30 |
+ "attachments": [], |
|
| 31 |
+ "raw_excerpt": "test test", |
|
| 32 |
+ "excerpt": "test test", |
|
| 33 |
+ "id": 6454342343, |
|
| 34 |
+ "created_at": "2014-04-17T10:25:31.000+02:00", |
|
| 35 |
+ "updated_at": "2014-04-17T10:25:31.000+02:00", |
|
| 36 |
+ "summary": "commented on whaat", |
|
| 37 |
+ "action": "commented on", |
|
| 38 |
+ "target": "whaat", |
|
| 39 |
+ "url": "https://basecamp.com/12456/api/v1/projects/76454545-explore-basecamp/messages/76454545-whaat.json", |
|
| 40 |
+ "html_url": "https://basecamp.com/12456/projects/76454545-explore-basecamp/messages/76454545-whaat#comment_76454545" |
|
| 41 |
+ } |
|
| 42 |
+ MD |
|
| 43 |
+ |
|
| 44 |
+ default_schedule "every_10m" |
|
| 45 |
+ |
|
| 46 |
+ def default_options |
|
| 47 |
+ {
|
|
| 48 |
+ 'username' => '', |
|
| 49 |
+ 'password' => '', |
|
| 50 |
+ 'user_id' => '', |
|
| 51 |
+ 'project_id' => '', |
|
| 52 |
+ } |
|
| 53 |
+ end |
|
| 54 |
+ |
|
| 55 |
+ def validate_options |
|
| 56 |
+ errors.add(:base, "you need to specify your basecamp username") unless options['username'].present? |
|
| 57 |
+ errors.add(:base, "you need to specify your basecamp password") unless options['password'].present? |
|
| 58 |
+ errors.add(:base, "you need to specify your basecamp user id") unless options['user_id'].present? |
|
| 59 |
+ errors.add(:base, "you need to specify the basecamp project id of which you want to receive events") unless options['project_id'].present? |
|
| 60 |
+ end |
|
| 61 |
+ |
|
| 62 |
+ def working? |
|
| 63 |
+ (events_count.present? && events_count > 0) |
|
| 64 |
+ end |
|
| 65 |
+ |
|
| 66 |
+ def check |
|
| 67 |
+ log "Requesting events from #{request_url}"
|
|
| 68 |
+ reponse = HTTParty.get request_url, auth_options.merge(:headers => {"User-Agent" => "Huginn (https://github.com/cantino/huginn)"})
|
|
| 69 |
+ memory[:last_run] = Time.now.utc.iso8601 |
|
| 70 |
+ if last_check_at != nil |
|
| 71 |
+ JSON.parse(reponse.body).each do |event| |
|
| 72 |
+ create_event :payload => event |
|
| 73 |
+ end |
|
| 74 |
+ end |
|
| 75 |
+ save! |
|
| 76 |
+ end |
|
| 77 |
+ |
|
| 78 |
+ private |
|
| 79 |
+ def first_run? |
|
| 80 |
+ memory[:first_run].nil? |
|
| 81 |
+ end |
|
| 82 |
+ |
|
| 83 |
+ def request_url |
|
| 84 |
+ since = memory[:last_run] ? "?since=#{memory[:last_run]}" : ''
|
|
| 85 |
+ "https://basecamp.com/#{URI.encode(options[:user_id].to_s)}/api/v1/projects/#{URI.encode(options[:project_id].to_s)}/events.json#{since}"
|
|
| 86 |
+ end |
|
| 87 |
+ |
|
| 88 |
+ def auth_options |
|
| 89 |
+ {:basic_auth => {:username =>options[:username], :password=>options[:password]}}
|
|
| 90 |
+ end |
|
| 91 |
+ end |
|
| 92 |
+end |
@@ -0,0 +1,21 @@ |
||
| 1 |
+[ |
|
| 2 |
+ {
|
|
| 3 |
+ "creator": {
|
|
| 4 |
+ "fullsize_avatar_url": "https://dge9rmgqjs8m1.cloudfront.net/global/dfsdfsdfdsf/original.gif?r=3", |
|
| 5 |
+ "avatar_url": "http://dge9rmgqjs8m1.cloudfront.net/global/dfsdfsdfdsf/avatar.gif?r=3", |
|
| 6 |
+ "name": "Dominik Sander", |
|
| 7 |
+ "id": 123456 |
|
| 8 |
+ }, |
|
| 9 |
+ "attachments": [], |
|
| 10 |
+ "raw_excerpt": "test test", |
|
| 11 |
+ "excerpt": "test test", |
|
| 12 |
+ "id": 6454342343, |
|
| 13 |
+ "created_at": "2014-04-17T10:25:31.000+02:00", |
|
| 14 |
+ "updated_at": "2014-04-17T10:25:31.000+02:00", |
|
| 15 |
+ "summary": "commented on whaat", |
|
| 16 |
+ "action": "commented on", |
|
| 17 |
+ "target": "whaat", |
|
| 18 |
+ "url": "https://basecamp.com/12456/api/v1/projects/5476464-explore-basecamp/messages/24598238-whaat.json", |
|
| 19 |
+ "html_url": "https://basecamp.com/12456/projects/5476464-explore-basecamp/messages/24598238-whaat#comment_150756301" |
|
| 20 |
+ } |
|
| 21 |
+] |
@@ -0,0 +1,80 @@ |
||
| 1 |
+require 'spec_helper' |
|
| 2 |
+ |
|
| 3 |
+describe Agents::BasecampAgent do |
|
| 4 |
+ before(:each) do |
|
| 5 |
+ stub_request(:get, /json$/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/basecamp.json")), :status => 200, :headers => {"Content-Type" => "text/json"})
|
|
| 6 |
+ stub_request(:get, /Z$/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/basecamp.json")), :status => 200, :headers => {"Content-Type" => "text/json"})
|
|
| 7 |
+ @valid_params = {
|
|
| 8 |
+ :username => "user", |
|
| 9 |
+ :password => "pass", |
|
| 10 |
+ :user_id => 12345, |
|
| 11 |
+ :project_id => 6789, |
|
| 12 |
+ } |
|
| 13 |
+ |
|
| 14 |
+ @checker = Agents::BasecampAgent.new(:name => "somename", :options => @valid_params) |
|
| 15 |
+ @checker.user = users(:jane) |
|
| 16 |
+ @checker.save! |
|
| 17 |
+ end |
|
| 18 |
+ |
|
| 19 |
+ describe "validating" do |
|
| 20 |
+ before do |
|
| 21 |
+ @checker.should be_valid |
|
| 22 |
+ end |
|
| 23 |
+ |
|
| 24 |
+ it "should require the basecamp username" do |
|
| 25 |
+ @checker.options['username'] = nil |
|
| 26 |
+ @checker.should_not be_valid |
|
| 27 |
+ end |
|
| 28 |
+ |
|
| 29 |
+ it "should require the basecamp password" do |
|
| 30 |
+ @checker.options['password'] = nil |
|
| 31 |
+ @checker.should_not be_valid |
|
| 32 |
+ end |
|
| 33 |
+ |
|
| 34 |
+ it "should require the basecamp user_id" do |
|
| 35 |
+ @checker.options['user_id'] = nil |
|
| 36 |
+ @checker.should_not be_valid |
|
| 37 |
+ end |
|
| 38 |
+ |
|
| 39 |
+ it "should require the basecamp project_id" do |
|
| 40 |
+ @checker.options['project_id'] = nil |
|
| 41 |
+ @checker.should_not be_valid |
|
| 42 |
+ end |
|
| 43 |
+ |
|
| 44 |
+ end |
|
| 45 |
+ |
|
| 46 |
+ describe "helpers" do |
|
| 47 |
+ it "should generate a correct auth hash" do |
|
| 48 |
+ @checker.send(:auth_options).should == {:basic_auth=>{:username=>"user", :password=>"pass"}}
|
|
| 49 |
+ end |
|
| 50 |
+ |
|
| 51 |
+ it "should not provide the since attribute on first run" do |
|
| 52 |
+ @checker.send(:request_url).should == "https://basecamp.com/12345/api/v1/projects/6789/events.json" |
|
| 53 |
+ end |
|
| 54 |
+ |
|
| 55 |
+ it "should provide the since attribute after the first run" do |
|
| 56 |
+ time = (Time.now-1.minute).iso8601 |
|
| 57 |
+ @checker.memory[:last_run] = time |
|
| 58 |
+ @checker.save |
|
| 59 |
+ @checker.reload.send(:request_url).should == "https://basecamp.com/12345/api/v1/projects/6789/events.json?since=#{time}"
|
|
| 60 |
+ end |
|
| 61 |
+ end |
|
| 62 |
+ describe "#check" do |
|
| 63 |
+ it "should not emit events on its first run" do |
|
| 64 |
+ expect { @checker.check }.to change { Event.count }.by(0)
|
|
| 65 |
+ end |
|
| 66 |
+ it "should check that initial run creates an event" do |
|
| 67 |
+ @checker.last_check_at = Time.now - 1.minute |
|
| 68 |
+ expect { @checker.check }.to change { Event.count }.by(1)
|
|
| 69 |
+ end |
|
| 70 |
+ end |
|
| 71 |
+ |
|
| 72 |
+ describe "#working?" do |
|
| 73 |
+ it "it is working when at least one event was emited" do |
|
| 74 |
+ @checker.should_not be_working |
|
| 75 |
+ @checker.last_check_at = Time.now - 1.minute |
|
| 76 |
+ @checker.check |
|
| 77 |
+ @checker.reload.should be_working |
|
| 78 |
+ end |
|
| 79 |
+ end |
|
| 80 |
+end |